<script setup lang="ts">
import { computed, onMounted, ref, watch } from "vue";
import { useRoute } from "vue-router";
import { useBooksStore } from "../stores/books";
import type { Mark } from "../stores/books";

const route = useRoute();
const store = useBooksStore();
const bookId = route.params.bookId as string;

const content = ref("");
const position = ref(0);
const fontSize = ref(18);
const theme = ref("light"); // light, sepia, dark
const container = ref<HTMLElement | null>(null);

const marks = ref<Mark[]>([]);

const percent = computed(() => {
  if (!content.value.length) return 0;
  return Math.min(100, Math.round((position.value / content.value.length) * 100));
});

const highlightedHtml = computed(() => {
  const s = content.value || "";
  const esc = (t: string) => t.replace(/&/g, "&amp;").replace(/</g, "&lt;").replace(/>/g, "&gt;");
  const sorted = [...marks.value]
    .map(m => ({ start: Math.max(0, Math.min(s.length, m.start)), end: Math.max(0, Math.min(s.length, m.end)) }))
    .filter(m => m.end > m.start)
    .sort((a, b) => a.start - b.start);
  let out = "";
  let cursor = 0;
  for (const m of sorted) {
    out += esc(s.slice(cursor, m.start));
    out += '<span class="hl">' + esc(s.slice(m.start, m.end)) + '</span>';
    cursor = m.end;
  }
  out += esc(s.slice(cursor));
  // preserve line breaks
  return out.replace(/\n/g, "<br>");
});

onMounted(async () => {
  const c = await store.getContent(bookId);
  content.value = c?.content ?? "";
  position.value = await store.getProgress(bookId);
  marks.value = await store.getMarks(bookId);
  // Scroll to position
  requestAnimationFrame(() => scrollToPosition());
});

watch(position, (p) => store.saveProgress(bookId, p));

function scrollToPosition() {
  if (!container.value) return;
  const before = content.value.slice(0, position.value);
  container.value.scrollTop = before.split("\n").length * (fontSize.value * 1.8);
}

function onScroll() {
  if (!container.value) return;
  // Approximate position by visible lines
  const lineHeight = fontSize.value * 1.8;
  const lines = Math.max(0, Math.floor(container.value.scrollTop / lineHeight));
  // Convert lines back to character index using a heuristic
  const charsPerLine = Math.max(20, Math.floor(container.value.clientWidth / (fontSize.value * 0.6)));
  position.value = Math.min(content.value.length - 1, lines * charsPerLine);
}

function changeFont(delta: number) {
  fontSize.value = Math.min(28, Math.max(14, fontSize.value + delta));
}

function setTheme(t: string) {
  theme.value = t;
}

// Selection -> mark
const selecting = ref(false);
const selText = ref<string>("");
let selStart = 0;
let selEnd = 0;
const noteText = ref("");

function handleMouseUp() {
  const s = window.getSelection();
  if (!s || s.isCollapsed) return;
  selText.value = s.toString();
  // Very rough mapping: use position + offset length
  selStart = position.value;
  selEnd = selStart + selText.value.length;
  selecting.value = true;
}
async function addMark(note?: string) {
  if (!selText.value) return;
  await store.addMark(bookId, selStart, selEnd, selText.value, note);
  selecting.value = false;
  selText.value = "";
  noteText.value = "";
  marks.value = await store.getMarks(bookId);
}
</script>

<template>
  <div class="reader" :class="theme">
    <div class="toolbar">
      <button @click="changeFont(-2)">A-</button>
      <div class="percent">{{ percent }}%</div>
      <button @click="changeFont(2)">A+</button>
      <div class="spacer" />
      <button @click="setTheme('light')">浅</button>
      <button @click="setTheme('sepia')">米</button>
      <button @click="setTheme('dark')">夜</button>
    </div>

    <div ref="container" class="content" @scroll="onScroll" @mouseup="handleMouseUp" :style="{ fontSize: fontSize + 'px', lineHeight: (fontSize*1.8) + 'px' }">
      <div class="text" v-html="highlightedHtml" />
    </div>

    <div class="progress">
      <input type="range" min="0" :max="content.length || 1" v-model.number="position">
    </div>

    <div v-if="selecting" class="mark-dialog">
      <div class="dialog">
        <div class="title">创建标记</div>
        <div class="text">“{{ selText.slice(0, 80) }}”</div>
        <div class="actions">
          <button @click="addMark()">仅高亮</button>
        </div>
        <div class="note-field">
          <textarea v-model="noteText" rows="3" placeholder="备注（可选）"></textarea>
          <div class="actions">
            <button @click="addMark(noteText)">保存备注</button>
            <button @click="selecting=false">取消</button>
          </div>
        </div>
      </div>
    </div>
  </div>
</template>

<style scoped>
.reader { display: flex; flex-direction: column; height: 100%; }
.toolbar { display: flex; align-items: center; gap: 8px; padding: 8px 12px; border-bottom: 1px solid #eee; background: var(--bg,#fff); }
.toolbar .spacer { flex: 1; }
.toolbar button { padding: 6px 10px; border: 1px solid #ddd; background: #fff; border-radius: 6px; }
.percent { color: #666; font-size: 12px; }
.content { flex: 1; overflow: auto; padding: 16px; background: var(--bg,#fff); color: var(--fg,#111); }
.content .text { white-space: normal; word-break: break-word; margin: 0; font-family: -apple-system,BlinkMacSystemFont,Segoe UI,Roboto,Helvetica,Arial,'PingFang SC','Microsoft Yahei',sans-serif; }
.content .hl { background: #ffed99; padding: 0 2px; border-radius: 3px; }
.progress { padding: 8px 12px; border-top: 1px solid #eee; background: var(--bg,#fff); }

.reader.light { --bg: #ffffff; --fg: #111; }
.reader.sepia { --bg: #f7f1e3; --fg: #3a2f2a; }
.reader.dark { --bg: #0f1115; --fg: #e6e6e6; }

.mark-dialog { position: fixed; inset: 0; background: rgba(0,0,0,0.4); display: flex; align-items: center; justify-content: center; }
.dialog { width: min(92vw, 420px); background: #fff; border-radius: 12px; padding: 16px; }
.dialog .title { font-weight: 600; margin-bottom: 8px; }
.dialog .text { font-size: 14px; color: #555; margin-bottom: 12px; }
.dialog .actions { display: flex; gap: 8px; justify-content: flex-end; }
.dialog .note-field { margin-top: 8px; }
.dialog textarea { width: 100%; border: 1px solid #ddd; border-radius: 8px; padding: 8px; font-size: 14px; }
</style>
